package cn.apthink.calendar;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class WorkDay {
	private LocalDate current;
	private Day day;
	private int worker;

	public WorkDay(LocalDate current) {
		this.current = current;
	}

	public boolean isWork() {
		return worker > 0 && day != null && day.getDuration() > 0;
	}

	public LocalDateTime getStartTime() {
		return !isWork() ? null : current.atStartOfDay().plusSeconds(day.getTimeRanges().get(0).getStart());
	}

	public LocalDateTime getEndTime() {
		return !isWork() ? null
				: current.atStartOfDay().plusSeconds(day.getTimeRanges().get(day.getTimeRanges().size() - 1).getEnd());
	}

	public String getStartTimeStr() {
		return !isWork() ? null : getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
	}

	public String getEndTimeStr() {
		return !isWork() ? null : getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
	}

	public int duration() {
		return !isWork() ? 0 : day.getDuration();
	}

	public int durationNormal() {
		return !isWork() ? 0 : day.getDurationNormal();
	}

	public int durationOvertime() {
		return !isWork() ? 0 : day.getDurationOvertime();
	}

	public int capacity() {
		return !isWork() ? 0 : day.getDuration() * worker;
	}

	public int capacityNormal() {
		return !isWork() ? 0 : day.getDurationNormal() * worker;
	}

	public int capacityOvertime() {
		return !isWork() ? 0 : (day.getDuration() - day.getDurationNormal()) * worker;
	}

	public int calcDuration(LocalDateTime start) {
		if (!isWork())
			return 0;
		LocalDateTime st = getStartTime();
		LocalDateTime et = getEndTime();
		if (!start.isAfter(st)) {
			return day.getDuration();
		} else if (!start.isBefore(et)) {
			return 0;
		} else {
			int s = !start.isAfter(st) ? day.getStart()
					: (int) (Duration.between(current.atStartOfDay(), start).toMillis() / 1000);
			int e = day.getEnd();
			return day.calcDuration(s, e);
		}
	}

	public int calcDuration(LocalDateTime start, LocalDateTime end) {
		if (!isWork())
			return 0;
		LocalDateTime st = getStartTime();
		LocalDateTime et = getEndTime();
		if (!start.isAfter(st) && !end.isBefore(et)) {
			return day.getDuration();
		} else if (!end.isAfter(st) || !start.isBefore(et)) {
			return 0;
		} else {
			int s = !start.isAfter(st) ? day.getStart()
					: (int) (Duration.between(current.atStartOfDay(), start).toMillis() / 1000);
			int e = !end.isBefore(et) ? day.getEnd()
					: (int) (Duration.between(current.atStartOfDay(), end).toMillis() / 1000);
			return day.calcDuration(s, e);
		}
	}

	public long calcCapacity(LocalDateTime start) {
		return calcDuration(start) * worker;
	}

	public long calcCapacity(LocalDateTime start, LocalDateTime end) {
		return calcDuration(start, end) * worker;
	}

	//David: 负载计算（考虑人数）
	public LocalDateTime calcEndTime(LocalDateTime startTime, long loadding) throws RuntimeException {
		if (!isWork()) {
			throw new RuntimeException("当前不是工作日");
		}
		return calcEndTime(startTime, Math.round(loadding/worker));
	}
	
	//David：时长计算（不考虑人数）
	public LocalDateTime calcEndTime(LocalDateTime startTime, int offSecond) throws RuntimeException {
		if (!isWork()) {
			throw new RuntimeException("当前不是工作日");
		}
		LocalDateTime d = startTime;
		if (d.isAfter(getEndTime()))
			return getEndTime();
		if (d.isBefore(getStartTime()))
			d = getStartTime();
		int startSecond = (int) (Duration.between(current.atStartOfDay(), d).toMillis() / 1000);
		startSecond = day.getValid(startSecond, offSecond);
		return current.atStartOfDay().plusSeconds(startSecond);
	}

	public LocalDateTime getValidWorkTime(LocalDateTime currentTime) {
		return calcEndTime(currentTime, 0);
	}

	@Override
	public int hashCode() {
		return Objects.hash(current);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		WorkDay other = (WorkDay) obj;
		return Objects.equals(current, other.current);
	}

	public static WorkDay testData() {
		WorkDay workDay = new WorkDay();
		Day day = Day.testData();
		workDay.setCurrent(LocalDate.parse("2024-02-14"));
		workDay.setDay(day);
		workDay.setWorker(1);
		return workDay;
	}

}
